
#include <cstdlib>
#include <iostream>
#include <cassert>

#include <math.h>

#include "SDL.h"
#include "SDL_opengl.h"
#include "LogUtil.h"

#include "common.h"

#include "Room.h"

using namespace std;

__BEGIN_NAMESPACE_DECL_

// RoomTexture Constructor
RoomTexture::RoomTexture (unsigned int texId, 
                          double sMax,
                          double tMax)
{
    _texId = texId;
    _sMax  = sMax;
    _tMax  = tMax;
}

// Room Constructor
Room::Room (unsigned int subdiv)
    : _subdiv(subdiv)
{ 
    _useTextures = false;
}

// Getters
unsigned int Room::getSubdivisions() { return _subdiv; }

// Setters
void Room::setUseTexture       (bool useTextures) { _useTextures = useTextures;}
void Room::setSubdivisions     (unsigned int subdiv) { _subdiv = subdiv; }
void Room::setFloorTexture     (const RoomTexture& tex) { _floor = tex; }
void Room::setCeilingTexture   (const RoomTexture& tex) { _ceil = tex; }
void Room::setFrontWallTexture (const RoomTexture& tex) { _front = tex; }
void Room::setBackWallTexture  (const RoomTexture& tex) { _back = tex; }
void Room::setLeftWallTexture  (const RoomTexture& tex) { _left = tex; }
void Room::setRightWallTexture (const RoomTexture& tex) { _right = tex; }


void Room::draw()
{
    GLfloat mAmbient[] = {0.2, 0.2, 0.2, 1.0};
    GLfloat mDiffuse[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat mSpecular[] = {0.0, 0.0, 0.0, 1.0};
    double x1, y1;
    double x2, y2;
    double thickness = 1.0;

    x1 = y1 = -0.5;
    x2 = y2 =  0.5;

    // Save current matrix
    glPushMatrix();

    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, mAmbient);
    glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mDiffuse);
    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mSpecular);

    // Apply any translation, rotation or scaling factors set for this object
    transform();

    // Rotate x-axis by 90 degrees.  We draw the object in the x/y planes,
    // so rotating it here will make the object "upright"
    glRotated (-90, 1.0, 0.0, 0.0);

    // Set the color to white
    glColor3d (1.0, 1.0, 1.0);

    // Save state
    glPushAttrib (GL_TEXTURE_BIT | GL_ENABLE_BIT);
    
    // Enable texture mapping
    if (_useTextures)
        glEnable (GL_TEXTURE_2D);

    // Ceiling
    glPushMatrix();
      glTranslated(0.0, 0.0, thickness/2.0);
      glRotated (180, 1.0, 0.0, 0.0);
      DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_ceil);
    glPopMatrix();


    // sides of the 3D rectangle
    // y=0.5 side
    glPushMatrix();
      glTranslated (0.0, 0.5, 0.0);
      glRotated (90, 1.0, 0.0, 0.0);
      DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_front);
    glPopMatrix();

    // y=-0.5 side
    glPushMatrix();
      glTranslated (0.0, -0.5, 0.0);
      glRotated (180, 0.0, 1.0, 0.0);
      glRotated (-90, 1.0, 0.0, 0.0);
      DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_back);
    glPopMatrix();

    // x=-0.5 side
    glPushMatrix();
      glTranslated (0.5, 0.0, 0.0);
      glRotated ( 90, 1.0, 0.0, 0.0);
      glRotated (-90, 0.0, 1.0, 0.0);
      DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_left);
    glPopMatrix();

    // x=0.5 side
    glPushMatrix();
      glTranslated (-0.5, 0.0, 0.0);
      glRotated (90, 1.0, 0.0, 0.0);
      glRotated (90, 0.0, 1.0, 0.0);
      DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_right);
    glPopMatrix();

    // Floor
    glTranslated(0.0, 0.0, -thickness/2.0);
    DrawSubdividedRectangle(x1,y1,x2,y2,_subdiv,_floor);

    // Restore state
    glPopAttrib();

    // Restore matrix
    glPopMatrix();
}

void
Room::DrawSubdividedRectangle (double x1, double y1, double x2, double y2, 
                               unsigned int subdiv, const RoomTexture& tex)
{
    double xinc, yinc;
    double sInc, tInc;

    assert (x1 < x2);
    assert (y1 < y2);

    if (tex._texId != 0)
        glBindTexture (GL_TEXTURE_2D, tex._texId);

    xinc = (x2 - x1) / subdiv;
    yinc = (y2 - y1) / subdiv;
    sInc = tex._sMax / subdiv;
    tInc = tex._tMax / subdiv;

    for (size_t i=0; i < subdiv; i++)
    {
        double base_y = y1+(i*yinc);
        double tTex = 0.0+(i*tInc);
        //DEBUG << "tTex=" << tTex;

        glBegin(GL_QUAD_STRIP);
        glNormal3d (0.0, 0.0, 1.0);
        glTexCoord2d (0.0, tTex+tInc); glVertex3d (x1, base_y+yinc,0.0);
        glTexCoord2d (0.0, tTex);      glVertex3d (x1, base_y,     0.0);

        for (size_t j=0; j < subdiv; j++)
        {
            double base_x = x1+((j+1)*xinc);
            double sTex = 0.0+((j+1)*sInc);
            //DEBUG << "sTex=" << sTex;
            glTexCoord2d (sTex, tTex+tInc); glVertex3d (base_x, base_y+yinc,0.0);
            glTexCoord2d (sTex, tTex);      glVertex3d (base_x, base_y,     0.0);
        }
        glEnd();
    }
}



__END_NAMESPACE_DECL_
